package de.nak.notendb.action;

import java.util.List;
import java.util.Map;

import com.opensymphony.xwork2.ActionSupport;

import de.nak.notendb.model.Examination;
import de.nak.notendb.model.ExaminationResult;
import de.nak.notendb.model.ExaminationSubject;
import de.nak.notendb.model.Student;
import de.nak.notendb.service.exceptions.AccessToDatabaseNotPossibleException;
import de.nak.notendb.service.exceptions.NoExaminationResultAvailableException;
import de.nak.notendb.service.exceptions.NoExaminationSubjectAvailableException;
import de.nak.notendb.service.exceptions.NoExaminationTryPossibleException;
import de.nak.notendb.service.exceptions.NoStudentAvailableException;
import de.nak.notendb.service.interfaces.IExaminationResultService;
import de.nak.notendb.service.interfaces.IExaminationService;
import de.nak.notendb.service.interfaces.IExaminationSubjectService;
import de.nak.notendb.service.interfaces.IStudentService;
import de.nak.notendb.service.interfaces.ISupportService;

/**
 * Exam Action class
 * 
 * @author Christian Baumhof
 * 
 */
public class ExamAction extends ActionSupport {
	private static final long serialVersionUID = -34078795711357080L;

	/**
	 * The studentService interface.
	 */
	private IStudentService studentService;

	/**
	 * The supportService interface.
	 */
	private ISupportService supportService;

	/**
	 * The examinationSubjectService interface.
	 */
	private IExaminationSubjectService examinationSubjectService;

	/**
	 * The examinationResultService interface.
	 */
	private IExaminationResultService examinationResultService;

	/**
	 * The the examinationService interface.
	 */
	private IExaminationService examinationService;

	/**
	 * The selectedSubject id.
	 */
	private Long selectedSubjectId;

	/**
	 * The id.
	 */
	private Long id;

	/**
	 * The student object.
	 */
	private Student student;

	/**
	 * The number of tries.
	 */
	private Integer nrTries;

	/**
	 * The examination results.
	 */
	private List<ExaminationResult> results;

	/**
	 * The examination subject.
	 */
	private ExaminationSubject subject;

	/**
	 * The examination result.
	 */
	private ExaminationResult result;

	/**
	 * The examination.
	 */
	private Examination examination;

	/**
	 * The grades.
	 */
	private Map<Float, Float> grades;

	/**
	 * The boolean which says if new try allowed.
	 */
	private Boolean errorNoNewTryAllowed;

	/**
	 * Execute Methode for loading objects
	 */
	@Override
	public String execute() throws Exception {
		// load student
		try {
			student = studentService.getStudent(id);
		} catch (NoStudentAvailableException exception) {
			return "DATA_NOT_FOUND";
		}

		// load subject
		try {
			subject = examinationSubjectService
					.getExaminationSubject(selectedSubjectId);
		} catch (NoExaminationSubjectAvailableException exception) {
			return "DATA_NOT_FOUND";
		}

		// load results and nr tries
		if (result == null) {
			results = examinationResultService
					.listAllValidExaminationResultsOfAStudentAndASubject(id,
							selectedSubjectId);
			nrTries = examinationResultService.getCountExaminationResult(
					selectedSubjectId, id);
			if (nrTries > 0) {
				result = results.get(nrTries - 1);
				examination = result.getExamination();
			}
		} else {
			nrTries = results.size();
		}

		// load valid grades
		grades = supportService.getValidGrades();

		// initialise errorNoNewTryAllowed
		if (errorNoNewTryAllowed == null) {
			errorNoNewTryAllowed = false;
		}

		return SUCCESS;
	}

	/**
	 * Method for adding an examination
	 * 
	 * @return status
	 */
	public String add() {
		try {
			if (examination == null) {
				examination = examinationService.createExamination(null,
						new String(), new String());
			} else {
				examination = examinationService.createExamination(
						examination.getId(), examination.getDate(),
						examination.getLecturer());
			}
			result = examinationResultService.addExaminationResult(
					selectedSubjectId, id, examination);
			for (int i = 0; i < nrTries; i++) {
				results.set(i, examinationResultService
						.getExaminatioResult(results.get(i).getId()));
			}
			nrTries++;
			results.add(result);
		} catch (NoExaminationTryPossibleException e) {
			errorNoNewTryAllowed = true;
		} catch (NoExaminationResultAvailableException e) {
			return "DATA_NOT_FOUND";
		} catch (NoStudentAvailableException e) {
			return "DATA_NOT_FOUND";
		}
		return SUCCESS;
	}

	/**
	 * Method for canceling an existing examination
	 * 
	 * @return status
	 */
	public String cancel() {
		ExaminationResult deleteResult;
		try {
			deleteResult = examinationResultService.getExaminatioResult(result
					.getId());
			result = examinationResultService
					.cancelExaminationResult(deleteResult);
		} catch (NoExaminationResultAvailableException exception) {
			return "DATA_NOT_FOUND";
		} catch (AccessToDatabaseNotPossibleException exception) {
			return ERROR;
		}
		return SUCCESS;
	}

	/**
	 * Method to save the examination result
	 * 
	 * @return status
	 */
	public String save() {
		ExaminationResult saveResult;
		try {
			saveResult = examinationResultService.getExaminatioResult(result
					.getId());
			saveResult.setGrade(result.getGrade());
			saveResult.setTypist(result.getTypist());
			saveResult.getExamination().setDate(examination.getDate());
			saveResult.getExamination().setLecturer(examination.getLecturer());
			result = examinationResultService.saveExaminationResult(saveResult);
		} catch (NoExaminationResultAvailableException exception) {
			return "DATA_NOT_FOUND";
		} catch (AccessToDatabaseNotPossibleException exception) {
			return ERROR;
		}
		return SUCCESS;
	}

	/**
	 * Returns the selected subjects id.
	 * 
	 * @return a subjects id.
	 */
	public Long getSelectedSubjectId() {
		return selectedSubjectId;
	}

	/**
	 * Setter for the selected subject id
	 * 
	 * @param selected
	 *            subject id
	 */
	public void setSelectedSubjectId(Long selectedSubjectId) {
		this.selectedSubjectId = selectedSubjectId;
	}

	/**
	 * Returns the id.
	 * 
	 * @return id.
	 */
	public Long getId() {
		return id;
	}

	/**
	 * Setter for the id
	 * 
	 * @param id
	 */
	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * Returns a student.
	 * 
	 * @return a student.
	 */
	public Student getStudent() {
		return student;
	}

	/**
	 * Returns number of tries.
	 * 
	 * @return tries.
	 */
	public Integer getNrTries() {
		return nrTries;
	}

	/**
	 * Setter for the number of tries
	 * 
	 * @param number
	 *            of tries
	 */
	public void setNrTries(Integer nrTries) {
		this.nrTries = nrTries;
	}

	/**
	 * Returns examination results.
	 * 
	 * @return examination results.
	 */
	public List<ExaminationResult> getResults() {
		return results;
	}

	/**
	 * Setter for the examination results
	 * 
	 * @param examination
	 *            results
	 */
	public void setResults(List<ExaminationResult> results) {
		this.results = results;
	}

	/**
	 * Setter for the student service
	 * 
	 * @param student
	 *            service
	 */
	public void setStudentService(IStudentService studentService) {
		this.studentService = studentService;
	}

	/**
	 * Setter for the examination subject service
	 * 
	 * @param examination
	 *            subject service
	 */
	public void setExaminationSubjectService(
			IExaminationSubjectService examinationSubjectService) {
		this.examinationSubjectService = examinationSubjectService;
	}

	/**
	 * Setter for the examination result service
	 * 
	 * @param examination
	 *            result service
	 */
	public void setExaminationResultService(
			IExaminationResultService examinationResultService) {
		this.examinationResultService = examinationResultService;
	}

	/**
	 * Returns the subject.
	 * 
	 * @return a examination subject.
	 */
	public ExaminationSubject getSubject() {
		return subject;
	}

	/**
	 * Returns examination result.
	 * 
	 * @return an examinationr esult.
	 */
	public ExaminationResult getResult() {
		return result;
	}

	/**
	 * Setter for the examination result
	 * 
	 * @param examination
	 *            result
	 */
	public void setResult(ExaminationResult result) {
		this.result = result;
	}

	/**
	 * Returns the examination.
	 * 
	 * @return the examination.
	 */
	public Examination getExamination() {
		return examination;
	}

	/**
	 * Setter for the examination
	 * 
	 * @param examination
	 */
	public void setExamination(Examination examination) {
		this.examination = examination;
	}

	/**
	 * Returns the grades.
	 * 
	 * @return the grades.
	 */
	public Map<Float, Float> getGrades() {
		return grades;
	}

	/**
	 * Setter for the support service
	 * 
	 * @param support
	 *            service
	 */
	public void setSupportService(ISupportService supportService) {
		this.supportService = supportService;
	}

	/**
	 * Returns if error no new try allowed.
	 * 
	 * @return if error no new try allowed.
	 */
	public Boolean getErrorNoNewTryAllowed() {
		return errorNoNewTryAllowed;
	}

	/**
	 * Setter for the examination service
	 * 
	 * @param examination
	 *            service
	 */
	public void setExaminationService(IExaminationService examinationService) {
		this.examinationService = examinationService;
	}

}
